package com.harmay.center.monitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.util.concurrent.RateLimiter;
import com.harmay.center.monitor.dto.CollectorDto;
import com.harmay.center.monitor.entity.MetricBaseMapping;
import com.harmay.center.monitor.entity.MetricSeverity;
import com.harmay.center.monitor.mapper.MetricBaseMappingMapper;
import com.harmay.center.monitor.mapper.MetricSeverityMapper;
import com.harmay.center.monitor.service.DingMonitorService;
import com.harmay.center.monitor.service.MetricBaseMappingService;
import com.harmay.center.monitor.service.MetricSendTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.harmay.center.monitor.task.RateLimiterTask.limitMap;

/**
 * @author Zuper
 * @version 1.0
 * @date 2022/8/31 15:55
 */
@Service
@Slf4j
public class MetricBaseMappingServiceImpl implements MetricBaseMappingService, InitializingBean {
    @Autowired
    private MetricBaseMappingMapper metricBaseMappingMapper;

    @Autowired
    private MetricSeverityMapper metricSeverityMapper;

    @Autowired
    private DingMonitorService dingMonitorService;

    @Autowired
    private List<MetricSendTypeService> metricSendTypeServices;

    public final static Map<String, MetricSendTypeService> typeServiceMap = new ConcurrentHashMap<>();

    public static Map<String, RateLimiter> map = null;

    @Override
    public void handleMetric(CollectorDto dto) {
        log.info("collect metric to handling,dto --> {}", dto);
        if (Objects.nonNull(dto)) {
            String subject = dto.getSubject();
            String level = dto.getSeverity();
            RateLimiter rateLimiter = limitMap.get(subject);
            if (rateLimiter.tryAcquire(1, 1000 * 10, TimeUnit.MILLISECONDS)) {
                QueryWrapper<MetricSeverity> severityQueryWrapper = new QueryWrapper<>();
                severityQueryWrapper.eq("level", level);
                MetricSeverity severity = metricSeverityMapper.selectList(severityQueryWrapper).get(0);

                QueryWrapper<MetricBaseMapping> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("subject_name", subject);
                List<MetricBaseMapping> metricBaseMappings = metricBaseMappingMapper.selectList(queryWrapper);
                String sendType = severity.getSendType();
                List<String> sendTypes = Arrays.asList(sendType.split(","));
                sendTypes.stream().forEach(type -> {
                    MetricSendTypeService service = typeServiceMap.get(type);
                    try {
                        service.handle(metricBaseMappings, dto.getMessage(), null);
                    } catch (IOException e) {
                        log.error("", e);
                    }
                });
            }
        }
    }

    @Override
    public void handleMetricWithUsers(CollectorDto dto) {
        log.info("collect metric to handling,dto --> {}", dto);
        if (Objects.nonNull(dto)) {
            String subject = dto.getSubject();
            String level = dto.getSeverity();
            List<String> users = dto.getUsers();
            RateLimiter rateLimiter = limitMap.get(subject);
            if (rateLimiter.tryAcquire(1, 1000 * 10, TimeUnit.MILLISECONDS)) {
                QueryWrapper<MetricSeverity> severityQueryWrapper = new QueryWrapper<>();
                severityQueryWrapper.eq("level", level);
                MetricSeverity severity = metricSeverityMapper.selectList(severityQueryWrapper).get(0);

                QueryWrapper<MetricBaseMapping> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("subject_name", subject);
                List<MetricBaseMapping> metricBaseMappings = metricBaseMappingMapper.selectList(queryWrapper);
                String sendType = severity.getSendType();
                List<String> sendTypes = Arrays.asList(sendType.split(","));
                sendTypes.stream().forEach(type -> {
                    MetricSendTypeService service = typeServiceMap.get(type);
                    try {
                        service.handle(metricBaseMappings, dto.getMessage(), users);
                    } catch (IOException e) {
                        log.error("", e);
                    }
                });
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        metricSendTypeServices.forEach(x -> {
            typeServiceMap.put(x.typeChoose(), x);
        });
    }
}
